package me.helllp.dake.generator.meta;

import freemarker.template.TemplateException;
import lombok.Getter;
import lombok.Setter;
import me.helllp.dake.common.anno.MataGenerator;
import me.helllp.dake.generator.config.ProjectConfiguration;
import me.helllp.dake.generator.config.enums.ProjectTypeEnum;
import me.helllp.dake.generator.meta.third.RdbmsMetaData;
import me.helllp.dake.generator.utils.FileAndPathUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.ObjectUtils;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 服务元数据信息
 */
public abstract class ProjectMetaData extends AbstractMetaData {
    /**
     * 原始项目的配置信息
     */
    @Getter
    @Setter
    private ProjectConfiguration projectConfiguration;

    @Getter
    @Setter
    private ProjectTypeEnum projectType;

    @Getter
    @Setter
    private String name;

    @Getter
    @Setter
    private String desc;

    @Getter
    @Setter
    private String basePath;

    @Getter
    @Setter
    private String basePackage;

    /**
     * 服务的POM定义
     */
    @MataGenerator
    @Getter
    private PomMetaData pom;

    /**
     * 运行中生成：项目Base路径
     */
    @MataGenerator
    @Getter
    private String projectPath;

    /**
     * 运行中生成：Java代码路径
     */
    @MataGenerator
    @Getter
    private String srcJavaPath;

    /**
     * 运行中生成：资源路径信息
     */
    @MataGenerator
    @Getter
    private String srcResourcePath;

    /**
     * 运行中生成：测试代码路径
     */
    @MataGenerator
    @Getter
    private String testJavaPath;

    /**
     * 运行中生成：测试代码路径
     */
    @MataGenerator
    @Getter
    private String testResourcePath;

    /**
     * 服务配置信息
     */
    @MataGenerator
    @Getter
    private Map<String,Object> configMaps;

    /**
     * 服务元数据信息
     */
    @MataGenerator
    @Getter
    private ServiceMetaData serviceMetaData;

    /**
     * 三方组件信息列表
     */
    @MataGenerator
    @Getter
    private List<IThirdComponent> thirdComponents;

    public ProjectMetaData(ProjectConfiguration projectConfiguration) throws IOException, InvocationTargetException, IllegalAccessException, TemplateException {
        this.projectConfiguration = projectConfiguration;
        // 属性拷贝
        BeanUtils.copyProperties(this, projectConfiguration);
        // 初始化属性设置
        initMetaData();
    }

    @Override
    public void initMetaData() throws IOException, InvocationTargetException, IllegalAccessException, TemplateException {
        this.pom = new PomMetaData();
        BeanUtils.copyProperties(this.pom, projectConfiguration);
        // 项目路径 = 基础路径+项目名称
        projectPath = FileAndPathUtils.pathAppend(this.basePath, name).getCanonicalPath();
        // Java源码路径 = 项目路径 + src/main/java
        srcJavaPath = FileAndPathUtils.pathAppend(projectPath, "src/main/java").getCanonicalPath();
        srcResourcePath = FileAndPathUtils.pathAppend(projectPath, "src/main/resources").getCanonicalPath();
        // 测试路径
        testJavaPath = FileAndPathUtils.pathAppend(projectPath, "src/test/java").getCanonicalPath();
        testResourcePath = FileAndPathUtils.pathAppend(projectPath, "src/test/resources").getCanonicalPath();

        if (!ObjectUtils.isEmpty(this.projectConfiguration.getServiceConfiguration())) {
            // 服务配置信息
            this.serviceMetaData = new ServiceMetaData(this.projectConfiguration.getServiceConfiguration());
            // 配置文件信息设置
            this.configMaps = serviceMetaData.getConfigMap();
        }

        // 处理三方键信息
        this.thirdComponents = new ArrayList<>();

        if (projectConfiguration.getServiceConfiguration().getDbConfig() != null) {
            RdbmsMetaData metaData = new RdbmsMetaData(projectConfiguration.getServiceConfiguration().getDbConfig());
            this.thirdComponents.add(metaData);
        }
    }

    public <T> T searchThirdMetaData(Class<T> _clazz) {
        return (T)this.getThirdComponents().stream().filter(data -> data.getClass().equals(_clazz)).findFirst().get();
    }
}
